package com.yc.mybatis.core;

import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Enumeration;
import java.util.Vector;

/**
 * 数据库连接池
 * Company 源晨信息
 * @author navy
 * @date 2023年2月20日
 * Email haijunzhou@hnit.edu.cn
 */
public class ConnectionPool {


	private String driver;
	private String url;
	private String username;
	private String password;
	
	private int initConnections = 5;  //初始化连接数
	private int maxConnections = 20;  //最大连接数
	private int incrementConnections = 5; //连接池中连接数不够时，每次增加多少
	private Vector<PoolConnection> connections; //存放创建的连接
	

	public ConnectionPool(String driver, String url, String username, String password) {
		super();
		this.driver = driver;
		this.url = url;
		this.username = username;
		this.password = password;
	}

	public ConnectionPool() {
		super();
	}

	public int getInitConnections() {
		return initConnections;
	}

	public void setInitConnections(int initConnections) {
		this.initConnections = initConnections;
	}

	public int getMaxConnections() {
		return maxConnections;
	}

	public void setMaxConnections(int maxConnections) {
		this.maxConnections = maxConnections;
	}

	public int getIncrementConnections() {
		return incrementConnections;
	}

	public void setIncrementConnections(int incrementConnections) {
		this.incrementConnections = incrementConnections;
	}
	
	public Vector<PoolConnection> getConnections() {
		return connections;
	}
	/**
	 *  创建连接池
	 * @author acer
	 *
	 */
	public synchronized void createPool() throws Exception {
		if(connections != null) {
			 return;
		}
		
		//加载获得驱动
		Driver driver =  (Driver) Class.forName(this.driver).newInstance();
		
		//注册驱动(登记驱动)
		DriverManager.registerDriver(driver);
		
		//初始化连接池列表
		connections = new Vector<PoolConnection>();
		
		//创建指定数据的初始化连接数
		createConnections(this.initConnections);
		
		System.out.println("创建连接池成功。。。。。。");
	}


	/**
	 * 创建指定连接数的方法
	 * @param initConnections
	 * @throws SQLException 
	 */
	private void createConnections(int initConnections) throws SQLException {
		for(int i =0;i<initConnections;i++) {
			if(this.maxConnections >0 && this.connections.size() >= this.maxConnections) {
				return;
				
			}
			//创建一个连接到连接池
			connections.addElement(new PoolConnection(newConnection(), this.connections.size() + 1));
		}
		
	}
	/**
	 * 创建一个新连接的方法
	 * @return
	 * @throws SQLException
	 */
	private Connection newConnection() throws SQLException {
		Connection con = DriverManager.getConnection(url,username,password);  //获取一个新的连接
		
		//判断是不是第一个创建，如果第一次创建，则要判断最大连接数是否合理
		if(connections.size() == 0) {
			DatabaseMetaData metaData = con.getMetaData();
			int driverMaxConnections = metaData.getMaxConnections(); //获取数据库所支持的最大连接数
			System.out.println(driverMaxConnections);
			if(driverMaxConnections >0 && driverMaxConnections < this.maxConnections) {
				this.maxConnections = driverMaxConnections;
			}
		}
		return con;
	}
	
	/*
	 * 获取一个可用连接的方法
	 */
	public synchronized Connection getConnection() {
		//说明连接池没有初始化
		if(connections == null || connections.isEmpty()) {
			return null;
		}
		
		Connection con = null;
	
			try {
				con  = getFreeConnection();
				while(con == null) {
					wait(1000);
					con = getFreeConnection();
					
				}
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		
		return con;
	}
	
	/**
	 * 等待的方法
	 * @return
	 */
	
	private void wait(int mseconds) {
		try {
			Thread.sleep(mseconds);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		//TimeUnit.SECONDS.sleep(1)
	}
	
	/**
	 * 获取空闲连接方法
	 * @return
	 * @throws SQLException
	 */
	private Connection getFreeConnection() throws SQLException {
		Connection con = findConnection();
		if(con == null) {//如果获取不到可用的连接
			createConnections(incrementConnections);//先扩容
			con = findConnection();//再找一下
			
			if(con == null) {
				return null;
			}
		}
		
		return con;
	}
   
	private Connection findConnection() {
		Connection con =null;
		PoolConnection pool = null;
		Enumeration<PoolConnection> enumerate = connections.elements();
		while(enumerate.hasMoreElements()) {
			pool = enumerate.nextElement();  //获得下一个连接对象
		   if(!pool.isBusy()) {//说明是空闲的
				con = pool.getConnection(); //获取这个连接对象中的连接
				pool.setBusy(true);
				
				if(!testConnection(con)) {  //测试这个连接是否可用
					//创建一个新的连接来替换这个不可以用的连接
					try {
						con = newConnection();
					} catch (SQLException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
					pool.setConnection(con);// 替换掉这个连接对象中的连接
					
				}
				System.out.println(pool.getPid() + "号连接为你服务。。。。。。。。。");
				break;
			}
		}
		return con;
	}
    /**
     * 测试连接是否可用
     * @param con
     * @return
     */
	private boolean testConnection(Connection con) {
		try {
			con.setAutoCommit(true);//这是数据库事务提交方式为自动提交
		} catch (SQLException e) {
			closeConnection(con);
			e.printStackTrace();
			return false;
		}  
		
		return true;
	}
	/**
	 * 释放连接
	 * @param con
	 */
	private void closeConnection(Connection con) {
		if(con != null) {
			try {
				con.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		
	}
    /**
     * 释放连接的方法
     * @param con
     */
	public void freeConnection(Connection con) {
		if(con == null) {
			return;
		}
		
		PoolConnection pool = null;
		Enumeration<PoolConnection> enumerate = connections.elements();
		while(enumerate.hasMoreElements()) {
			pool = enumerate.nextElement();
			if(con == pool.getConnection()) {
				pool.setBusy(false);
				return;
			}
			
		}
	}
	/**
	 * 关闭连接池的方法
	 */
	public synchronized void closeConnectionPool() {
		if(connections == null) {
			return;
		}
		PoolConnection pool = null;
		Enumeration<PoolConnection> enumerate = connections.elements();
		while(enumerate.hasMoreElements()) {
			pool = enumerate.nextElement();
			if(pool.isBusy()) {//说明这个连接还在用
				wait(5000); //等五秒
				
			}
			closeConnection(pool.getConnection()); //关闭连接
			connections.removeElement(pool);//从连接池中释放对象
			
		}
		connections = null;
	}
	
	public class PoolConnection {
		private Connection connection = null; //连接对象
		private boolean busy = false; //是否空闲
		private int pid;  //连接编号
		
		@Override
		public String toString() {
			return "PoolConnection [connection=" + connection + ", busy=" + busy + ", pid=" + pid + "]";
		}
		
		public PoolConnection(Connection connection, int pid) {
			super();
			this.connection = connection;
			this.pid = pid;
		}
		
		public PoolConnection() {
			super();
			// TODO Auto-generated constructor stub
		}
		
		public Connection getConnection() {
			return connection;
		}
		
		public void setConnection(Connection connection) {
			this.connection = connection;
		}
		
		public boolean isBusy() {
			return busy;
		}
		
		public void setBusy(boolean busy) {
			this.busy = busy;
		}
		
		public int getPid() {
			return pid;
		}
		
		public void setPid(int pid) {
			this.pid = pid;
		}
		
	}
}
